package com.lan.shiro;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Configuration
public class ShiroConfig {

    //标记不需要认证的资源
    private static final String ANON = "anon";
    //未登录跳转页面
    private static final String LOGIN_URL = "/sys/login";
    //登录后访问未授权站点跳转
    private static final String UNAUTHORIZED_URL = "/error/404";
    //白名单
    private static final String[] WHITE = {
            "/favicon.ico",
            "/css/**",
            "/img/**",
            "/js/**",
            "/layUI/**",
            LOGIN_URL,
            UNAUTHORIZED_URL,
            "/sys/demo",
            "/rainbow/**",
            "/pearAdminLayUI/**",
    };

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl(LOGIN_URL);
        shiroFilterFactoryBean.setUnauthorizedUrl(UNAUTHORIZED_URL);
        //添加自定义Filter，放行OPTIONS请求
//        Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
//        filters.put("security", new AccessFilter());
//        shiroFilterFactoryBean.setFilters(filters);
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        for (String s : WHITE) {
            filterChainDefinitionMap.put(s, ANON);
        }
        //退出过滤器
        filterChainDefinitionMap.put("/sys/loginOut", "logout");
        //其它都需要授权
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 安全认证管理
     *
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        List<Realm> realms = new ArrayList<>();
        realms.add(getCustomRealm());
        securityManager.setRealms(realms);
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    /**
     * Shiro生命周期处理器
     *
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 开启shiro的注解(如@RequiresRoles,@RequiresPermissions)，加入spring-boot-starter-aop
     *
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 身份认证realm
     *
     */
    @Bean
    public CustomRealm getCustomRealm() {
        return new CustomRealm();
    }

    /**
     * cookie管理对象
     *
     * */
    @Bean
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        return cookieRememberMeManager;
    }

    /**
     * cookie对象
     *
     * */
    @Bean
    public SimpleCookie rememberMeCookie() {
        //cookie的名称，对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //记住我cookie生效时间30天
        simpleCookie.setMaxAge(259200);
        return simpleCookie;
    }
}
